home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / src / dicehelp / DICEHelp.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  26KB  |  1,016 lines

  1. /*
  2.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  3.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  4.  *    DICE-LICENSE.TXT.
  5.  */
  6. /*
  7. **    $Id: DICEHelp.c,v 30.0 1994/06/10 18:05:48 dice Exp $
  8. **
  9. **    Dice help system.  Searches an index file for a given
  10. **    keyword.  Returns either filename information, or the actual
  11. **    clip to the console, clipboard, or Rexx RESULT.
  12. **
  13. */
  14. /*
  15. **
  16. **    BUGS
  17. **        REXXSTARTUP should exit if already resident.  (No, kill old).
  18. **
  19. **        Looses $30 (48) bytes of memory when started from Workbench.
  20. **
  21. **        CLI/WB invocation should use resident index file
  22. **
  23. **              If memory is less than XX bytes free, flush self on exit.
  24. **
  25. **        DICEHelp from Workbench accounts for "reasonable" font
  26. **        sizes.    Very large font sizes, however, blow it up.
  27. **
  28. **    !!!TODO
  29. **        If cursor is on "console.doc" in
  30. **              "work:doc/doc/console.doc/OpenDevice",
  31. **        return the console doc in full.
  32. **
  33. **        (Return # of lines for editor to open window?
  34. **        Useful for small clips).
  35. **
  36. **        Make search faster -- check case insensitive first.
  37. **        (Actually this is obsolete -- new tokenized index file
  38. **        is needed to deal with automatic multiple references).
  39. **
  40. **        Match plural mismatch with error index of -3? (See error
  41. **        weighting system).
  42. **
  43. **              Workbench won't read full files directly.
  44. **
  45. **    New HELP Items:
  46. **        Put Carolyn's 68000 cards on line.  She says this is OK,
  47. **                      with credit.
  48. **
  49. **        Help on error messages.
  50. **
  51. **        Help on C keywords
  52. **
  53. */
  54. #define D(x)    ;
  55. #define    X(x)    ;
  56. #undef CLIPSUPPORT      /* Enable/disable clipboard.device code.
  57.         Clipboard support is slightly broken right now, but could be fixed */
  58.  
  59. #include <clib/exec_protos.h>
  60. #include <clib/alib_protos.h>
  61. #include <rexx/rxslib.h>
  62. #include <clib/rexxsyslib_protos.h>
  63. #include <dos/dos.h>
  64. #include <exec/memory.h>
  65. #ifdef  CLIPSUPPORT
  66. #include <devices/clipboard.h>
  67. #endif
  68. #include <DICEHelp_rev.h>
  69.  
  70. #include <strings.h>
  71. #include <stdio.h>
  72. #include <ctype.h>
  73.  
  74.  
  75. /*******************************************************************************
  76. **    Errors.
  77. */
  78. #define OK_TEMPFILE      1      // Tempfile has been created
  79. #define OK_FULLFILE      2      // Full path name has been returned
  80. #define ERROR_NOTOOLTYPE 3    // No VIEWER tooltype
  81. #define ERROR_NOTFOUND     4    // Can't find search string
  82. #define ERROR_BADFORMAT  5    // Badly formatted line in index file
  83. #define ERROR_BADCOMMAND 6    // Unrecognised AREXX command
  84. #define ERROR_READFILE     7    // Error reading help file
  85. #define ERROR_NOMEMORY     8    // Out of memory error
  86. #define ERROR_WRITEFILE  9    // Error writing temporary file to T:    !!!
  87. #define ERROR_NOCLIP     10    // Can't open clipboard.device          !!!
  88. #define ERROR_NOCLIPSUP     11    // Don't even support clipboard
  89. #define ERROR_INTERNAL     12    // Ohh, baby!
  90. #define    ERROR_MAXERRNO     12    // Distinguish error from pointer
  91.  
  92. struct ExtRexxMsgPort {
  93.    struct MsgPort  rmp_Port;
  94.    struct MinList  rmp_SearchNodes;
  95. };
  96.  
  97. struct SearchNode {
  98.     struct MinNode    sn_Node;    // Linkage
  99.     char *        sn_FileName;    // Full path to load file from
  100.     char *        sn_FileData;    // Loaded file, or NULL if unloaded
  101.     unsigned long    sn_FileSize;    // Length of file, if known
  102. };
  103.  
  104. #define unless(x)    if(!(x))
  105. #define until(x)    while(!(x))
  106.  
  107. /*******************************************************************************
  108. **    Prototypes
  109. */
  110. void    *rexxOpen(void);
  111. void     rexxClose(void);
  112. void     rexxReply(struct RexxMsg *msg,int Result1,int Result2,char *string);
  113.  
  114. void    *clipOpen(void);
  115. void     clipClose(void);
  116. LONG     clipWrite(char *string);
  117. LONG     clipLongWrite(LONG *ldata);
  118. char    *getHelp(int outmode, char *searchline, int curpos);
  119.  
  120. char    *searchOpen(void);
  121. void     searchClose(void);
  122. char    *searchMe(char *strings,char *searchfor,char **filename);
  123. void     convertFile(char *file,ULONG length);
  124.  
  125. void     debugPrintSN(void);
  126.  
  127. void     startOutput( char outmode );
  128. void     sendOutput( char outmode, char *outstring, ULONG outlength );
  129. char    *endOutput( char outmode );
  130.  
  131. char    *StringScan( char *instring );
  132. char    *tailpath_p( char *searchline );
  133. int     isCollectable(char c);
  134. char    *ErrorText( int error, void * auxdata );
  135.  
  136. /*******************************************************************************
  137. **    Globals
  138. */
  139. struct RsxLib        *RexxSysBase    =0;    // Rexxsyslib.library base
  140. struct MsgPort        *rexxPort    =0;    // Our Rexx port
  141.  
  142. struct IOClipReq    *clipIO    =0;        // Clipboard Access
  143. struct List         SearchNodes;        // List of struct SearchNode
  144.  
  145. char             rexxName[]="DICEHELP";    // !! No string optimization
  146. #define                 PORT_PRI        5       // Slighly above the rabble
  147. const char  IdString[] = { VERSTAG };
  148.  
  149. #define OUTMODE_CLIP        'C'
  150. #define OUTMODE_STDOUT        'S'
  151. #define OUTMODE_FILE        'T'
  152. #define    OUTMODE_CRUTCHES    'Z'
  153.  
  154. #define COMMAND_QUIT        'Q'
  155.  
  156.  
  157. #define TEMPFILE_NAME        "t:DICEHelp.temp"       // hard coded, too
  158. #define    TEMPFILE_LEN        15    // DICE has no strlen() optimization
  159.  
  160.  
  161. disable_break()
  162. {
  163.     return(0);
  164. }
  165.  
  166. /*******************************************************************************
  167. **
  168. **    Workbench support
  169. */
  170. #include "intuition/intuition.h"
  171. #include <clib/intuition_protos.h>
  172. #include <clib/icon_protos.h>
  173. #include <workbench/workbench.h>
  174. #include <workbench/startup.h>
  175.  
  176. #define STRING_MAX 90                // !! Fixed size
  177. char    buf_string[STRING_MAX];         // !! Fixed size
  178. char    inp_string[STRING_MAX];         // !! Fixed size
  179. char    commandline[STRING_MAX];        // !! Fixed size
  180.  
  181. #define GX    10
  182. #define GY    25
  183. #define GWIDTH    400
  184. #define GHEIGHT 30
  185.  
  186. struct StringInfo si =
  187. {
  188. inp_string,    // String
  189. NULL,        // Undo
  190. 0,        // Buffer position
  191. STRING_MAX,    // Count
  192. 0,        // Disp Pos
  193. 0,        // Undo pos
  194. 0,        // Num    Chars
  195. 0,        // DispCount
  196. 0,0,        // CLeft,CTop
  197. NULL,        // Layer
  198. 0,        // LongInt
  199. NULL        // Alternate keymap
  200. };
  201.  
  202. struct Gadget gt =
  203. {
  204. NULL,
  205. GX,GY,
  206. GWIDTH,GHEIGHT,
  207. GADGHBOX,
  208. RELVERIFY,
  209. STRGADGET,
  210. NULL,
  211. NULL,
  212. NULL,
  213. 0,
  214. &si,
  215. 0,
  216. NULL
  217. };
  218.  
  219. struct NewWindow nw =
  220. {
  221. ((640-GWIDTH+20)/2),75,     /* Left, Top */
  222. GWIDTH+20,GHEIGHT+20,
  223. -1,-1,
  224. IDCMP_CLOSEWINDOW|IDCMP_GADGETUP,
  225. WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|
  226. WFLG_SMART_REFRESH|WFLG_ACTIVATE,
  227. >,
  228. NULL,
  229. "DICEHelp: Please enter a word:",
  230. NULL,NULL,
  231. 0,0,
  232. 0,0,
  233. WBENCHSCREEN
  234. };
  235.  
  236.  
  237. int wbmain(struct WBStartup *wbs)
  238. {
  239. struct Window        * win;
  240. struct IntuiMessage    * msg=0;
  241. char            * filename=0;
  242. char            * temp=0;
  243.  
  244. int              rc=0;
  245.  
  246.     if ( win=OpenWindow(&nw) ) {
  247.     SetAPen(win->RPort,2);
  248.     if ((win->Height-win->BorderBottom-1) > 0) {
  249.         RectFill(win->RPort,
  250.          win->BorderLeft,
  251.          win->BorderTop,
  252.          win->Width-win->BorderRight-1,
  253.          win->Height-win->BorderBottom-1,
  254.          );
  255.         }
  256.     ActivateGadget(>,win,NULL);
  257.  
  258.  
  259.     // Collect VIEWER tooltype into commandline array, else
  260.     // set RC=ERROR_NOTOOLTYPE
  261.     {
  262.     struct DiskObject    * dob;    // DICEHelp icon (for Tooltypes)
  263.     BPTR              saveLock;
  264.     saveLock = CurrentDir((BPTR)wbs->sm_ArgList[0].wa_Lock);
  265.     if (dob = GetDiskObject(wbs->sm_ArgList[0].wa_Name)) {
  266.         if (temp=FindToolType(dob->do_ToolTypes,"VIEWER") ) {
  267.         strncpy(commandline,temp,STRING_MAX-TEMPFILE_LEN-2);
  268.         strncat(commandline," ",STRING_MAX);
  269.         strncat(commandline,TEMPFILE_NAME,STRING_MAX);
  270.         } else {
  271.         SetWindowTitles(win,"No \"VIEWER\" ToolType in icon!",(void *)-1);
  272.         rc= ERROR_NOTOOLTYPE;
  273.         // Window stays open for message, but user can't do anything.
  274.         }
  275.         FreeDiskObject(dob);
  276.     }
  277.     CurrentDir(saveLock);
  278.     }
  279.  
  280.  
  281.     unless( searchOpen() ) {
  282.         SetWindowTitles(win,"Can't open file \"s:DICEHelp.index\"!",(void *)-1);
  283.         rc= ERROR_READFILE;
  284.         // Window stays open for message, but user can't do anything.
  285.         }
  286.  
  287.     // Loop until we process a message (Any message causes us to exit
  288.     int looping=1;
  289.     while(looping && Wait(1L << win->UserPort->mp_SigBit))
  290.     {
  291.         while(msg = (struct IntuiMessage *) GetMsg(win->UserPort) )
  292.         {
  293.         switch( msg->Class )
  294.         {
  295.             case CLOSEWINDOW:
  296.             looping=0;
  297.             break;
  298.             case GADGETUP:
  299.             if (!rc) {
  300.                 char *msg;
  301.                 SetWindowTitles(win, commandline,(void *)-1);
  302.                 msg = getHelp( OUTMODE_FILE, inp_string, 0 );
  303.                 if (msg == NULL)
  304.                    msg = "E Internal error!";
  305.                 if (msg[0] != 'T') {
  306.                 DisplayBeep(0L);
  307.                 SetWindowTitles(win, msg+2, (void *)-1);
  308.                 looping=1;    // Stay, show message
  309.                 ActivateGadget(>,win,NULL);    // Re-juice gadget
  310.                 } else {
  311.                 //
  312.                 // !!!! :TODO:
  313.                 // Under 2.0: fh=Open("CON:0/0/200/200/DICEHelp Error/AUTO/CLOSE/WAIT",MODE_NEWFILE);
  314.                 // Under 1.3: fh=Open("NIL:",MODE_NEWFILE);
  315.                 //
  316.                 // Note: Execute does not return a sane code under 2.0!
  317.                 //
  318.                 if( Execute(commandline,NULL,Open("NIL:",MODE_NEWFILE)) )
  319.                     looping=0;
  320.                 else
  321.                     DisplayBeep(0L);
  322.                 }
  323.             }
  324.             break;
  325.             default:
  326.         }
  327.         ReplyMsg( (struct Message *)msg );
  328.         }
  329.     }
  330.     if (win)    CloseWindow(win);
  331.     searchClose();
  332.  
  333.     }    // OpenWindow
  334. }
  335.  
  336.  
  337. /*******************************************************************************
  338. **    CLI Startup
  339. */
  340. main(int argc,char * argv[])
  341. {
  342. struct RexxMsg *msg;
  343.  
  344. char    *filename=0;
  345. char    *refline =0;
  346.  
  347. char    *temp=0;
  348. char     outmode=0;
  349. char    *rexxresult=0;
  350. int     returncode=0;
  351.  
  352.     onbreak( disable_break );
  353.  
  354.     if (argc != 2 || ( argc == 2  &&  *argv[1]=='?' ) ) {
  355.     printf("DICEhelp <Searchstring> [REXXSTARTUP]\n");
  356.     printf("; Return help for searchstring.  See MakeIndex & s:DICEHelp.index\n");
  357.     exit(5);
  358.     }
  359.  
  360.     unless( searchOpen() ) {
  361.         puts( ErrorText( ERROR_READFILE, "s:DICEHelp.index" ));
  362.     exit(10);       // !!! Modify to return REXX result
  363.     }
  364.  
  365.     if( strcmp(argv[1],"REXXSTARTUP") )
  366.     {
  367.             temp=getHelp( OUTMODE_STDOUT, argv[1], 0 );
  368.                 unless( temp[0] == 'S')
  369.                         puts( temp+2 ); // Error
  370.     }
  371.     else{    // REXXSTARTUP
  372.     unless( rexxOpen() ) {    // !!! Error check
  373.         printf("Error: Can't open \"rexxsyslib.library\"\n");
  374.         }
  375.         #ifdef  CLIPSUPPORT
  376.     unless( clipOpen() ) {
  377.         printf("Error: Can't open \"clipboard.device\"\n");
  378.         }
  379.         #endif
  380.  
  381.     D(printf("REXX port open for traffic!\n"));
  382.  
  383.     until( outmode == 'Q' || SIGBREAKF_CTRL_C &
  384.            Wait(1L << rexxPort->mp_SigBit | SIGBREAKF_CTRL_C) ) {
  385.         while( msg=(struct RexxMsg *)GetMsg((struct MsgPort *)rexxPort) ) {
  386.  
  387.         temp = msg->rm_Args[0];
  388.         D(printf("Message %lx, rm_Args[0] @ %lx:\n%s\n",msg,temp,temp));
  389.  
  390.         rexxresult=0;
  391.         returncode = ERROR_BADCOMMAND;
  392.         if( (3 < strlen(temp)) && (temp[1]==' ') )
  393.             {
  394.             outmode = temp[0];
  395.             printf("Outmode = %c\n", outmode);
  396.             if ( outmode == 'Q' )
  397.             rexxresult = "QUITTING";
  398.             else if ( outmode == 'Z' )
  399.             rexxresult = getHelp( OUTMODE_FILE, &temp[2], -1 );
  400.             else
  401.             rexxresult = getHelp( OUTMODE_FILE, &temp[2], 0 );
  402.             }
  403.         if( rexxresult )
  404.             returncode = 0;
  405.         rexxReply( msg,returncode,0,rexxresult );
  406.         }  // While messages
  407.         }       // Until exit
  408.         #ifdef  CLIPSUPPORT
  409.     clipClose();
  410.         #endif
  411.     rexxClose();
  412.     }
  413.  
  414.     D(printf("Exiting...\n"));
  415.     searchClose();
  416.     return(returncode);
  417. }
  418.  
  419. #ifdef    NOTDEF
  420. /*******************************************************************************
  421. **    Debug functions
  422. */
  423. void debugPrintSN(void)
  424. {
  425. struct SearchNode *nd=(struct SearchNode *)&SearchNodes;
  426.  
  427.     while((nd=nd->sn_Node.mln_Succ) && (nd->sn_Node.mln_Succ)) {
  428.         printf("SearchNode at %lx\n",nd);
  429.         printf("sn_FileName     =%s\n",nd->sn_FileName);
  430.         printf("sn_FileSize     =%ld\n",nd->sn_FileSize);
  431.         printf("sn_FileData     =%lx\n\n",nd->sn_FileData);
  432.         }
  433. }
  434. #endif
  435.  
  436. /*******************************************************************************
  437. **    Index file functions
  438. */
  439. #define FILE_PAD    2    // Stick two NULLs at the end of the file
  440.  
  441. char *searchOpen(void)
  442. {
  443. struct    SearchNode *sn;
  444. ULONG    fh=0;
  445. ULONG    length;
  446. char    *body=0;
  447. char    *filename="s:DICEHelp.index";
  448.  
  449.     NewList(&SearchNodes);
  450.  
  451.     if (fh=Open(filename,MODE_OLDFILE)) {
  452.     Seek(fh,0,OFFSET_END);
  453.     if (length=Seek(fh,0,OFFSET_BEGINNING)) {
  454.         if (sn=AllocMem(sizeof(struct SearchNode),0)) {
  455.         sn->sn_FileName=filename;
  456.         sn->sn_FileData=0;
  457.         sn->sn_FileSize=length+FILE_PAD;
  458.         AddTail(&SearchNodes,(struct Node *)sn);
  459.         if (body=AllocMem(length+FILE_PAD,0)) {
  460.             if (length==Read(fh,body,length)) {
  461.             sn->sn_FileData=body;
  462.             convertFile(body,length);    // LF->NULL & Terminate
  463.             } else {
  464.             FreeMem(body,sn->sn_FileSize);
  465.             }
  466.             }
  467.         }
  468.         }
  469.     }
  470.  
  471.     if(fh)
  472.     Close(fh);
  473.  
  474.     return(body);
  475. }
  476.  
  477. void searchClose(void)
  478. {
  479. struct SearchNode *sn;
  480. struct SearchNode *nn;
  481.  
  482.     nn=(struct SearchNode *)&SearchNodes;
  483.     nn=(struct SearchNode *)nn->sn_Node.mln_Succ;
  484.  
  485.     while( nn && nn->sn_Node.mln_Succ) {
  486.     sn=nn;
  487.     nn=(struct SearchNode *)nn->sn_Node.mln_Succ;
  488.  
  489.     D(printf("Freeing searchnode %s. %d bytes\n",sn->sn_FileName,
  490.           sn->sn_FileSize));
  491.  
  492.     if( sn->sn_FileData )
  493.         FreeMem(sn->sn_FileData,sn->sn_FileSize);
  494.     FreeMem(sn,sizeof(struct SearchNode));
  495.     }
  496. }
  497.  
  498. /*******************************************************************************
  499. **    Line parsing functions
  500. **
  501. **    Some editors have lousy "get word" functions.  Given a cursor
  502. **    position and a line, we can clip out words too.
  503. **
  504. **    ??    If the cursor is ON punctuation, return it    ??
  505. **
  506. **    The result is NULL or a pointer into the string.  The end of
  507. **    the parsed word is NULL terminated, ** MODIFYING ** the input.
  508. **
  509. **    Input lines are formatted with XX equal to the cursor position:
  510. **        Z XX Clipped line
  511. **    String is at least 4 characters long.
  512. **
  513. */
  514. int isCollectable(char c)
  515. {
  516.     if( isalnum(c) || c==':' || c=='/' || c=='_' || c=='.' || c=='\\' )
  517.         return( 1 );
  518.     return( 0 );
  519. }
  520.  
  521. char * StringScan( char *instring )
  522. {
  523. char    *tail;
  524. char    *result;
  525. unsigned long curpos;
  526. unsigned long curtemp;    //    Wordy()
  527.  
  528.     curpos = strtol( instring, &tail, 10 );
  529.     D(printf("|Input pos=%ld, Line=%s\n", curpos, tail));
  530.     if ( !curpos || (*tail != ' ') )    // !!! longer than string?
  531.         return( NULL );
  532.  
  533.     curtemp    = curpos;
  534.     while( curtemp && isCollectable( tail[curtemp-1] ) )
  535.         curtemp--;
  536.     result = &tail[curtemp];
  537.     D(printf("|Start pos=%ld, Tail=%s\n", curpos, result));
  538.  
  539.     curtemp = curpos;
  540.     while( isCollectable( tail[curtemp] ) )
  541.         curtemp++;    // Stops at trailing NULL, at worst
  542.     tail[curtemp]=0;
  543.     D(printf("|Final pos=%ld, Result=\"%s\"\n", curtemp, result) );
  544.  
  545.     if( curtemp == curpos )    // If no characters were valid
  546.         result = 0;
  547.     return( result );
  548. }
  549.  
  550.  
  551.  
  552. /*******************************************************************************
  553. **    Output functions. Start, send and end output based on outmode.
  554. */
  555. ULONG    outfh;            // For xxxOut functions
  556.  
  557. void startOutput(char outmode)
  558. {
  559.     switch(outmode) {
  560.         case OUTMODE_CLIP:    // !!! IFF FTXT Length
  561.             outfh=1;
  562.             break;
  563.         case OUTMODE_STDOUT:
  564.             outfh=1;        // Continuation flag, basically
  565.             break;
  566.         case OUTMODE_FILE:
  567.         case OUTMODE_CRUTCHES:
  568.             outfh=Open( TEMPFILE_NAME, MODE_NEWFILE );
  569.             break;
  570.         default:
  571.     }
  572. }
  573.  
  574.  
  575. void sendOutput(char outmode, char *outstring,ULONG outlength)
  576. {
  577. char *returnstring=0;
  578.  
  579.     switch(outmode) {
  580.         case OUTMODE_CLIP:
  581.                     #ifdef      CLIPSUPPORT
  582.             clipWrite(outstring);
  583.                     #endif
  584.                 break;
  585.         case OUTMODE_STDOUT:
  586.             while( outfh && outlength && (outlength=nextLine(outstring)) ) {
  587.             if( outlength != fwrite(outstring,1,outlength,stdout) )
  588.                 outlength=0;       // Terminate early
  589.             if( SIGBREAKF_CTRL_C & SetSignal( 0,SIGBREAKF_CTRL_C) ) {
  590.                 outfh = 0;
  591.                 outlength=0;
  592.                 }
  593.             outstring += outlength;
  594.             }
  595.             break;
  596.         case OUTMODE_FILE:
  597.         case OUTMODE_CRUTCHES:
  598.             if( outfh )
  599.             if( outlength != Write( outfh,outstring,outlength )) {
  600.                 Close( outfh );    // Prevent multiple "failed"
  601.                 outfh = NULL;    // requesters in case of error
  602.                 }
  603.             break;
  604.         default:
  605.     }
  606. }
  607.  
  608.  
  609. //  !! This strings should be moved to ErrorText for localization
  610. char *endOutput( char outmode )
  611. {
  612. char *returnstring="E Internal error!";
  613.  
  614.     switch(outmode) {
  615.         case OUTMODE_CLIP:
  616.             returnstring="E Clipboard not supported";
  617.             break;
  618.         case OUTMODE_STDOUT:
  619.             returnstring="S stdout";
  620.             break;
  621.         case OUTMODE_FILE:
  622.         case OUTMODE_CRUTCHES:
  623.             if( outfh )
  624.             Close( outfh );
  625.             outfh = NULL;
  626.             returnstring="T t:DICEHelp.temp";
  627.             break;
  628.         default:
  629.     }
  630.     return( returnstring );
  631. }
  632.  
  633.  
  634. /*******************************************************************************
  635. **    Arexx functions
  636. */
  637. void * rexxOpen(void)
  638. {
  639.     RexxSysBase = (struct RxsLib *)OpenLibrary("rexxsyslib.library",0L);
  640.  
  641.     if (rexxPort == NULL) {
  642.     Forbid();
  643.     if (!( rexxPort = FindPort(rexxName ) ))
  644.         rexxPort = CreatePort(rexxName, PORT_PRI);
  645.     Permit();
  646.     }
  647.  
  648.     return( RexxSysBase );
  649. }
  650.  
  651. void rexxClose(void)
  652. {
  653.     if (RexxSysBase) {
  654.     CloseLibrary(RexxSysBase);
  655.     RexxSysBase=NULL;
  656.     }
  657.  
  658.     if (rexxPort)
  659.     DeletePort(rexxPort);
  660. }
  661.  
  662. void rexxReply(struct RexxMsg *msg,int Result1,int Result2,char *string)
  663. {
  664.     msg->rm_Result1 = Result1;
  665.     msg->rm_Result2 = Result2;
  666.  
  667.     if (Result1 == 0 && (msg->rm_Action & (1L << RXFB_RESULT))) {
  668.     D(printf("Rexx Result1=%lx  Result2=%s\n",0,string));
  669.     if (string && RexxSysBase)
  670.         msg->rm_Result2 =
  671.         (LONG)CreateArgstring(string, (LONG)strlen(string)) ;
  672.     else
  673.         msg->rm_Result2 = NULL;
  674.     }
  675.     D(printf("Rexx Result1=%lx  Result2 =%lx\n",msg->rm_Result1,msg->rm_Result2));
  676.  
  677.     ReplyMsg((struct Message *)msg);
  678. }
  679.  
  680. #ifdef  CLIPSUPPORT
  681. /******************************************************************************
  682. **    Clipboard functions
  683. */
  684. void * clipOpen()
  685. {
  686. struct MsgPort *port;
  687.  
  688.     if    (port = CreatePort(0L, 0L))
  689.     {
  690.     if  (clipIO = (struct IOClipReq *)
  691.         CreateExtIO (port, sizeof (struct IOClipReq)) )
  692.         {
  693.         unless( OpenDevice ("clipboard.device", 0, clipIO, 0) )
  694.         return(clipIO);
  695.  
  696.         DeleteExtIO(clipIO);
  697.         clipIO = NULL;
  698.         }
  699.     DeletePort(port);
  700.     }
  701.  
  702.     return(0);
  703. }
  704.  
  705. void clipClose()
  706. {
  707.     if( clipIO ) {
  708.         CloseDevice(clipIO);
  709.         DeletePort(clipIO->io_Message.mn_ReplyPort);
  710.         DeleteExtIO(clipIO);
  711.         }
  712. }
  713.  
  714. LONG clipWrite(char * string)
  715. {
  716.     LONG length, slen = strlen (string);
  717.     BOOL odd = (slen & 1);    /* pad byte flag */
  718.     LONG error = 0L;
  719.  
  720.     /* Reset the clip id */
  721.     clipIO->io_ClipID = 0;
  722.  
  723.     length = (odd) ? slen + 1 : slen;
  724.     clipIO->io_Offset = 0;
  725.     error = clipLongWrite ((LONG *) "FORM");/* "FORM" */
  726.  
  727.     length += 12;
  728.     error = clipLongWrite (&length);    /* #  */
  729.     error = clipLongWrite ((LONG *) "FTXT");/* "FTXT" for example */
  730.     error = clipLongWrite ((LONG *) "CHRS");/* "CHRS" for example */
  731.     error = clipLongWrite (&slen);        /* #  (length of string) */
  732.  
  733.     clipIO->io_Command = CMD_WRITE;
  734.     clipIO->io_Error = 0;
  735.     clipIO->io_Data = (char *) string;
  736.     clipIO->io_Length = slen;        /* length of string */
  737.     error = (LONG) DoIO (clipIO);    /* text string */
  738.  
  739.     /* Write the pad byte */
  740.     if (odd)
  741.     {
  742.     clipIO->io_Command = CMD_WRITE;
  743.     clipIO->io_Error = 0;
  744.     clipIO->io_Data = NULL;
  745.     clipIO->io_Length = 1;
  746.     error = (LONG) DoIO (clipIO);
  747.     }
  748.  
  749.     /* Indicate that we're done writing to the clipboard */
  750.     clipIO->io_Command = CMD_UPDATE;
  751.     clipIO->io_Error = 0;
  752.     error = (LONG) DoIO (clipIO);
  753.  
  754.     return (error);
  755. }
  756.  
  757. LONG clipLongWrite (LONG * ldata)
  758. {
  759.     clipIO->io_Command = CMD_WRITE;
  760.     clipIO->io_Error = 0;
  761.     clipIO->io_Data = (char *) ldata;
  762.     clipIO->io_Length = 4L;
  763.     return ( (LONG) DoIO (clipIO) );
  764. }
  765. #endif
  766.  
  767. /*******************************************************************************
  768. **    Clip & Snip functions
  769. */
  770. /*
  771. **    searchline    - Search word, or raw line from editor.
  772. **    curpos        - Cursor position on line, or zero for no parsing.
  773. **    outmode        - Where to stuff it.
  774. **
  775. **    returns:
  776. **        Filename clip is stored in, or name of entire file
  777. **        Multiple references
  778. **        Name of word searched for
  779. **
  780. **    errors:
  781. **        Clip not found
  782. **        Can't open file
  783. **        Bad format
  784. */
  785. char *getHelp(int outmode, char *searchline, int curpos)
  786. {
  787. struct SearchNode *sn=(struct SearchNode *)&SearchNodes; // Search
  788. int           rc=ERROR_NOTFOUND;             // Error code
  789.  
  790.         // searchline    // Passed: parameter, raw unprocessed line
  791. char    *       searchword;    // Parsed: Word to search for, ie "OpenDevice"
  792.  
  793. char          *refline;    // Searched: [searchname] [offset] [lines]
  794. char          *filename=0;    // Searched: Path name for refline
  795.  
  796. unsigned long    fh=0;
  797. unsigned long    startpos;    // Calculated from refline
  798. unsigned long    length;        // Calculated from refline
  799.  
  800. char    *    temp=0;        // Have bits, will travel.
  801. char    *    refline2;    // Multi-reference buffer
  802. char    *    filename2;    // Multi-reference buffer
  803.  
  804. char *    returnstring=0; // Indicates where to look for result.
  805.             // "CLIP"
  806.             // "STDOUT"
  807.             // "full:path"
  808.             // "t:DICEHelp.temp"
  809.  
  810.     /*
  811.     **    Parse it.  Use Z mode if a cursor position is given.
  812.     */
  813.     if( curpos ) {
  814.     searchline = StringScan( searchline );    // Null terminates searchline-
  815.     }                    // returns interesting part
  816.     if( searchline == NULL || strlen( searchline ) < 2 )
  817.         return( ErrorText( ERROR_NOTFOUND, "" ));
  818.  
  819.     /*
  820.     **  Clip off "device:filename/word" to just "word"
  821.     */
  822.     searchword = tailpath_p( searchline );
  823.     D(printf("\nWord=<%s> Line=<%s>\n",searchword, searchline ));
  824.     if( !*searchword )        // Help item contained a trailing :
  825.         return( ErrorText( ERROR_NOTFOUND, searchline ));
  826.  
  827.     /*
  828.     **  Search all lists of words.  Reject refline's that don't match
  829.     **  the expected file name.
  830.     */
  831.     refline = 0;
  832.     while( !refline && (sn=(struct SearchNode *)sn->sn_Node.mln_Succ) &&
  833.            (sn->sn_Node.mln_Succ)) {
  834.     if( sn->sn_FileData ) {
  835.         temp = sn->sn_FileData;
  836.         while( temp = searchMe(temp, searchword, &filename) ) {
  837.         D(printf("Search-Filename=%s res=%s cmp=%d\n",
  838.               filename, temp, strpathcmp( filename, searchline )));
  839.             if( !strpathcmp( filename, searchline ) ) {
  840.             refline = temp;
  841.             break;
  842.         }
  843.         temp += strlen( temp )+1;
  844.         }
  845.     }
  846.     }
  847.  
  848.     /*
  849.     **  Basic parsing of refernce line.  Checks for bad format, gets length
  850.     **  and offset.
  851.     */
  852.     unless( refline )
  853.         return( ErrorText( ERROR_NOTFOUND, searchword ));
  854.     unless( temp=strchr(refline,0x09) )    // Search for tab
  855.         return( ErrorText( ERROR_BADFORMAT, 0 ));
  856.     startpos=strtol(temp,&temp,16);
  857.     length=strtol(temp,&temp,16);
  858.     D(printf("Reading %s, startpos %lx, length %lx\nrefline=%s searchword=%s\n",
  859.         filename,startpos,length,refline,searchword));
  860.  
  861.     /*
  862.     **  If the index file specifies the *entire* file, and the mode is
  863.     **  tempfile, just return the full path name of the file.  This saves
  864.     **  reading the file twice, as well as memory.  Note: Multiple references
  865.     **  won't be shown; life sucks.
  866.     */
  867.     if ( outmode==OUTMODE_CRUTCHES && length==0 )
  868.         return( ErrorText( OK_FULLFILE, filename+1 ));
  869.  
  870.     if (fh=Open(filename+1, MODE_OLDFILE)) {
  871.     Seek(fh, startpos, OFFSET_BEGINNING);
  872.     unless( length ) {        // Zero length means read *all*
  873.         Seek(fh, 0, OFFSET_END);
  874.         length=Seek(fh, 0, OFFSET_BEGINNING);
  875.         }
  876.         unless( length )
  877.             return( ErrorText( ERROR_READFILE, filename+1 ) );
  878.     if (temp=AllocMem(length+1,0)) {
  879.         if (length==Read(fh, temp, length)) {
  880.         temp[length]=0;
  881.  
  882.         startOutput( outmode );
  883.         sendOutput( outmode, temp, length );
  884.         }
  885.         FreeMem(temp,length+1);
  886.         }
  887.         else{
  888.                return( ErrorText( ERROR_NOMEMORY, (void *)length ) );
  889.             }
  890.     Close(fh);
  891.     }
  892.     else{
  893.     return( ErrorText( ERROR_READFILE, filename+1 ) );
  894.         }
  895.  
  896.     /*
  897.     **    Multiple references section.  Yes, I hacked it in.
  898.     */
  899.     sprintf(buf_string,"# %s\\%s\n", filename+1, refline);   /* First line */
  900.     sendOutput( outmode, buf_string, strlen( buf_string ) );
  901.  
  902.     refline2  = refline;
  903.     filename2 = filename;
  904.     while( refline2 )
  905.     {
  906.     X(printf("Testing for more %s entries (%s)\n",searchword,refline2));
  907.  
  908.     refline2+=strlen( refline2 )+1;
  909.     refline2 =searchMe(refline2,searchword,&temp);
  910.         if( temp )
  911.                 filename2 = temp;       // If new filename, update
  912.  
  913.     if( refline2 )
  914.                 {
  915.         X(printf("Got it: File %s refline=%lx/%s\n",
  916.         filename2,refline2,refline2));
  917.  
  918.         strcpy (buf_string, "# ");
  919.         strncat(buf_string, filename2+1,    STRING_MAX);
  920.         strncat(buf_string, "\\",        STRING_MAX);
  921.         strncat(buf_string, refline2,            STRING_MAX);
  922.         strncat(buf_string, "\n",        STRING_MAX); // !!! ANSI Misfeature
  923.                 sendOutput( outmode, buf_string, strlen( buf_string ) );
  924.         }
  925.     }
  926.  
  927.     return( endOutput( outmode ) );
  928. }
  929.  
  930. /*
  931. **    Reverse case insensitive string compare specialized for paths
  932. **    Compare:
  933. **        Help Request    =    foo.doc/AllocMem
  934. **        Full path    =    work:doc/foo.doc
  935. **    If path part matches full path, return 0, else return 1.
  936. */
  937. int strpathcmp( path, candidate)
  938. const char *path;
  939. const char *candidate;
  940. {
  941. const char *pathe;
  942. const char *cande;
  943. typedef    unsigned char    ubyte;
  944.  
  945.     cande = tailpath_p( candidate );
  946.     if( cande == candidate )
  947.         return( 0 );        // Trivial case: No path to compare
  948.  
  949.     cande--;            // foo.doc/AllocMem
  950.     pathe = path+strlen(path);        //        ^
  951.  
  952.     while( (cande > candidate) && (pathe > path) ) {
  953.         pathe--;
  954.         cande--;
  955.         if (tolower(*(ubyte *)pathe) != tolower(*(ubyte *)cande))
  956.             return( 1 );
  957.         }
  958.     return( 0 );
  959. }
  960.  
  961.  
  962. /*
  963. **    Return just filename part of complete or incomplete path
  964. */
  965. char *tailpath_p( char *pathname )
  966. {
  967. char *    temp;
  968.  
  969.     if( temp=strrchr( pathname, '\\' ) )
  970.     return( ++temp );
  971.     else if( temp=strrchr( pathname, ':' ) )
  972.     return( ++temp );
  973.     else
  974.     return( pathname );
  975. }
  976.  
  977.  
  978. char *ErrorText( int error, void * auxdata )
  979. {
  980. char    * localstring;
  981.  
  982.     switch( error ) {
  983.         case OK_TEMPFILE:
  984.                 localstring = "T %s";
  985.                 break;
  986.         case OK_FULLFILE:
  987.                 localstring = "F %s";
  988.                 break;
  989.     case ERROR_NOTOOLTYPE:
  990.                 localstring = "E No \"VIEWER\" tooltype in icon!";
  991.                 break;
  992.     case ERROR_NOTFOUND:
  993.                 localstring = "E Item \"%s\" not found";
  994.                 break;
  995.     case ERROR_BADFORMAT:
  996.                 localstring = "E Corrupt line in s:DICEHelp.index";
  997.                 break;
  998.     case ERROR_BADCOMMAND:  // Handled as a rexx error number
  999.     case ERROR_READFILE:
  1000.                 localstring = "E Error reading \"%s\"";
  1001.                 break;
  1002.     case ERROR_NOMEMORY:    // Out of memory error        !!!
  1003.                 localstring = "E Out of memory - %d bytes needed";
  1004.                 break;
  1005.     case ERROR_WRITEFILE:    // Error writing temporary file to T: !!!
  1006.                 localstring = "E Error writing \"%s\"";
  1007.         break;
  1008.         default:
  1009.                 localstring = "E Internal error!";
  1010.     }
  1011.  
  1012.     sprintf( buf_string, localstring, auxdata );  // !!! Length limit
  1013.     return( buf_string );
  1014. }
  1015.  
  1016.